﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using LingDong.HtmlParser;
using LingDong.IndexEntities.Document;
using LingDong.SerializeProvider;
using NLog;

namespace LingDong.IndexCreator
{
    internal class DocumentIndex
    {
        #region Constructor

        internal DocumentIndex()
        {
            documentOffset = new Dictionary<int, DocumentOffset>();
            parsedDocumentList = new List<ParsedDocumentEntity>();
            originalDocumentList = new List<OriginalDocumentEnity>();
        }

        #endregion
        

        #region Internal Methods

        /// <summary>
        /// Add one document to document index, and return the parsed document
        /// </summary>
        /// <param name="url">url of the document</param>
        /// <param name="content">content of the document</param>
        /// <param name="isDataContainsOnlyText">if ture, html parse is needed</param>
        /// <returns>the parsed document</returns>
        internal ParsedDocumentEntity Add(string url, string content, bool isTextOnly)
        {
            try
            {
                int docID = parsedDocumentList.Count;

                OriginalDocumentEnity oriDoc = new OriginalDocumentEnity(docID, url, content);
                originalDocumentList.Add(oriDoc);

                string title = String.Empty;
                if (isTextOnly)
                    title = url;
                else
                    content = HtmlContent.ParseHtml(content, out title);
                
                ParsedDocumentEntity parsedDoc = new ParsedDocumentEntity(docID, url, title, content);
                parsedDocumentList.Add(parsedDoc);

                return parsedDoc;
            }
            catch (Exception ex)
            {
                Logger logger = LogManager.GetCurrentClassLogger();
                logger.Error("In subindex creator, document index, Add a parsed document: {0}", ex.Message);
                throw;
            }
        }

        /// <summary>
        /// After add enough documents to current sub index, save the document index to files
        /// </summary>
        /// <param name="docIndexFname">document index file name, generally X.DocumentIndex</param>
        /// <param name="parsedDocFname">parsed document content file name, generally X.ParsedDocument</param>
        /// <param name="oriDocFname">original document content file name, generally X.riginalDocument</param>
        internal void SaveToFile(string docIndexFname, string parsedDocFname, string oriDocFname)
        {
            try
            {
                Debug.Assert(parsedDocumentList.Count == originalDocumentList.Count);

                using (FileStream parsedDocStream = new FileStream(parsedDocFname, FileMode.Create))
                using (FileStream oriDocStream = new FileStream(oriDocFname, FileMode.Create))
                {
                    int docCount = parsedDocumentList.Count;
                    for (int i = 0; i < docCount; i++)
                    {
                        // record offset
                        DocumentOffset offset = new DocumentOffset(parsedDocStream.Position, oriDocStream.Position);
                        documentOffset.Add(i, offset);

                        // serialize pased doc
                        Serializer.Serialize<ParsedDocumentEntity>(parsedDocStream, parsedDocumentList[i]);
                        // serialize ori doc
                        Serializer.Serialize<OriginalDocumentEnity>(oriDocStream, originalDocumentList[i]);
                    }
                }

                // serialize document offset
                using (FileStream fs = new FileStream(docIndexFname, FileMode.Create))
                {
                    Serializer.Serialize<Dictionary<int, DocumentOffset>>(fs, documentOffset);
                }
            }
            catch (IOException ex)
            {
                Logger logger = LogManager.GetCurrentClassLogger();
                logger.Error("Error sub index creator, document index, save to files, IOException: {0}", ex.Message);
                throw;
            }
            catch (Exception ex)
            {
                Logger logger = LogManager.GetCurrentClassLogger();
                logger.Error("Error sub index creator, document index,save to files, Known Exception: {0}", ex.Message);
                throw;
            }
        }

        #endregion
        

        #region Private Members

        /// <summary>
        /// DocID, (parsed doc offset, ori doc offset)
        /// </summary>        
        private Dictionary<int, DocumentOffset> documentOffset;

        private List<ParsedDocumentEntity> parsedDocumentList;

        private List<OriginalDocumentEnity> originalDocumentList;

        #endregion
    }
}
